#include <iostream>
#include <vector>
#include <unordered_map>
using namespace std;

const float EPSION = 1e-5f;

template <typename T>
struct Point
{
    T x;
    T y;

    Point(T x, T y) : x(x), y(y) {}

    bool operator==(const Point<T> &p) const
    {
        if constexpr (is_floating_point_v<T>)
        {
            return abs(this->x - p.x) < EPSION && abs(this->y - p.y) < EPSION;
        }
        else
        {
            return this->x == p.x && this->y == p.y;
        }
    }
};

// Poit hash 实现
namespace std
{
    template <typename T>
    struct hash<Point<T>>;
}

template <typename T>
// requires std::is_interal_v<T>  // requires 是 c++20 特性
struct std::hash<Point<T>>
{
    size_t operator()(const Point<T> &p) const
    {
        static_assert(std::is_integral_v<T>, "Only support int type");
        size_t h1 = hash<T>()(p.x);
        size_t h2 = hash<T>()(p.y);
        return hash<T>()(h1 ^ (h2 << 1));
    }
};

template <>
struct std::hash<Point<float>>
{
    size_t operator()(const Point<float> &p) const
    {
        // 浮点数按精度转成整数
        long long px = static_cast<long long>(p.x / ESPIPE + 0.5);
        long long py = static_cast<long long>(p.y / ESPIPE + 0.5);
        // 计算hash
        return hash<long long>()(px ^ (py << 1));
    }
};

template <>
struct std::hash<Point<double>>
{
    size_t operator()(const Point<double> &p) const
    {
        // 浮点数按精度转成整数
        long long px = static_cast<long long>(p.x / ESPIPE + 0.5);
        long long py = static_cast<long long>(p.y / ESPIPE + 0.5);
        // 计算hash
        return hash<long long>()(px ^ (py << 1));
    }
};

template <typename T>
vector<int> filter_point(const vector<Point<T>> &p1, const vector<Point<T>> &p2)
{
    unordered_map<Point<T>, int> p1_map;
    vector<int> indexs;
    for (int i = 0; i < p1.size(); i++)
    {
        p1_map[p1[i]] = i;
    }

    for (const auto &p : p2)
    {
        auto it = p1_map.find(p);
        if (it != p1_map.end())
        {
            indexs.push_back(it->second);
        }
        else
        {
            indexs.push_back(-1);
        }
    }

    return indexs;
}
